 1.控制结构和函数之if 表达式
   
   Scala中 if 表达式有返回值。
   如果if 和 else 的返回值类型不一样，那么就返回两个返回值类型公共的父类。
   package lagou.cn.part02

object IfDemo {
  def main(args: Array[String]): Unit = {
    val num=20

    //在Scala中 if else语句是有返回值的，将if或else中最后一行语句作为返回值
    if(num>20) "jacky" else "lisi"

    //多分支if语句
    if(num<0)
      0
    else if(num==20)
      1
    else
      -1

    //因为if else语句有返回值，那么可以直接将if else语句赋值给一个变量
    // if else语句的返回值，不需要加return关键字
    val name = if (num > 20) "jacky" else "lisi"

    //如果if else语句中，两者的返回值类型不一样
    //此时Scala会自动推断出两者的公共类型，然后将公共类型作为表达式的返回值类型
    val name2:Any =if(num==20) "tom" else 100

    //如果if else语句中缺省了else语句块，那么默认的else的值就是Unit
    //Unit用()小括号表示，类似与java中的void
    val name3 = if (num > 20) "jacky"
    val name4 = if (num > 20) "jacky" else ()
  }
}


-- 如果返回的类型不一致就返回公共的父类
val s = if (x > 0)
  "positive"
else
  -1

-- 缺省 else 语句；s1/s2的返回类型不同
val s1 = if (x > 0) 1 等价 val s1 = if (x > 0) 1 else ()
val s2 = if (x > 0) "positive" 等价 val s2 = if (x > 0) "positive" else ()

 2.for 表达式
   
   Scala中，for循环语法结构：for (i <- 表达式 / 集合)，让变量 i遍历<-右边的表达式/集合的所有值。
   Scala为for循环提供了很多的特性，这些特性被称之为 for守卫式 或 for推导式。
   -- 基本结构。使用to实现左右两边闭合的访问区间

package lagou.cn.part02

/**
 * Scala拥有与与Java相同的while和do while循环
 * 但是没有与java for循环相对应的语法结构
 * Scala中的for：for (i <- 表达式 / 集合)，让循环变量 i遍历<-右边的表达式/集合的所有值
 * 注意：循环变量i前面没有用val 或 var来修饰，这个循环变量的类型是表达式或集合的元素类型
 * 循环变量的作用域一直持续到循环结束
 */
object ForDemo {
  def main(args: Array[String]): Unit = {
    //for基本结构,使用to实现左右两边闭合的访问区间[1,10]
    for (i <- 1 to 10) {
      println(s"i = $i")
    }
    //for基本结构,使用until实现左闭右开的访问区间[1,10)
    for (i <- 1 until (10)) {
      println(s"i = $i")
    }
    //双重循环，相当于java中的嵌套循环，条件之间用分号分隔
    println("==========================================================")
    for (i <- 1 to 3; j <- 1 to 5) {
      println(i*j)
    }
    println("=================循环中使用变量=========================")
    for (i <- 1 to 3; j = 4 - i) {
      println(i * j)
    }
    println("====================守卫式，增加了if条件语句===================")
    //注意：if前面没有分号
    for (i <- 1 to 10; j <- 1 to 10 if i==j) {
      println(s"i * j = $i * $j =${i*j}")
    }
    println("====================推导式，使用yield接收返回结果===================")
    //如果for循环的循环体yield开始，那么此循环会构造一个集合，每次迭代生成集合中的一个值
    //可以使用变量接收产生的新集合
    val result = for (i <- 1 to 5) yield i % 2
    result.foreach(println(_))

    println("====================九九乘法表===================")
    for (i <- 1 to 9; j <-1 to i) {
      print(s"$j * $i = ${i*j}\t")
      if(i==j) println()
    }
    println("====================for循环使用大括号===================")
    for {
      i <- 1 to 3
      from = 4 - i
      j <- from to 3
    }
     println(s"i=$i,j=$j")

    println("====================遍历字符串===================")
    val message="sparkscala"
    for(elem <- message) print(elem+ "")
  }

}


 3.while 表达式
   
   Scala提供了与 Java 类似的while和do...while循环。while语句的本身没有任何返回值类型，即while语
句的返回结果是Unit类型的 () 。
   Scala内置控制结构特地去掉了 break 和 continue。
   特殊情况下如果需要终止循环，可以有以下三种方式：
       使用Boolean类型的控制变量
       使用return关键字
       使用breakable和break，需要导入scala.util.control.Breaks包
	   
package lagou.cn.part02

object WhileDemo {
  def main(args: Array[String]): Unit = {
    var num = 1
//    while (num < 10) {
//      println(s"num = $num")
//      num += 1
//    }
//    do {
//      println(s"num = $num")
//      num += 1
//    } while (num < 10)


    //使用Boolean类型控制变量，终止循环
//    var flag = true
//    while (flag) {
//      println(s"num = $num")
//      num += 1
//      if(num==5) flag=false
//    }

    //使用return关键字终止循环
//    for (i <- 1 to 10) {
//      if(i==5) return
//      println(s"i=$i")
//    }

    //使用breakable和break，需要导入scala.util.control.Breaks包
    import scala.util.control.Breaks._
    var res=0
    breakable{
      for (i <- 1 until(10)) {
        if(i == 5) break()
        res += i
      }
    }
    println(res)
  }
}


 4.函数
   
   函数体中最后一句为返回值的话，可以将return 去掉；如果一个函数体只有一句代码，大括号可以去掉；
   如果一个函数没有返回值，其返回类型为Unit , 并且 “=” 号可以去掉，这样的函数被称为过程；
   可以不声明函数的返回类型，返回类型可通过自动类型推断来完成，但递归函数的返回类型必须声明；
   备注：建议明确声明函数的返回值，即使为Unit
   
package lagou.cn.part02

object FunctionDemo {
  /**
   * 定义函数的语法结构：def 函数名(参数列表):返回值类型={函数体}
   * 函数体中最后一条语句的返回值作为整个函数的返回值，返回值不需要使用return关键字
   * 也可以不声明函数的返回值类型，Scala会自动根据最后一条语句的返回值推断出函数的返回值类型
   * 但是，如果是递归函数，其返回值类型必须声明
   * 
   * @param num1
   * @param num2
   * @return
   */
  def add(num1: Int, num2: Int): Int = {
    num1 + num2
  }

  // 使用递归函数来计算阶乘
  def facrorial(num:Int):Long={
    if (num <= 1)
      1
    else
      num * facrorial(num - 1)
  }
  // 通过递归函数实现一个斐波那契数列：1,1,2,3,5,8......
  def fibonacci(n: Int): Long = {
      if (n == 1 || n == 2) {
        1
      } else {
        fibonacci(n - 1) + fibonacci(n - 2)
      }
  }

  //如果函数没有返回值，其返回值为Unit，类似与java中的void，"="也可以省略
  //在Scala中，没有返回值的函数称为过程
  def getSum(x: Int, y: Int): Unit = {
    println(x + y)
  }

  //函数中的参数可以有默认值，称为默认参数
  def add2(x: Int = 10, y: Int = 20): Unit = {
    x + y
  }
  //变长参数，参数类型右边加上*号
  //变长参数只能出现参数列表的尾部，并且只有一个
  //在Spark的源码中有大量的变长参数
  def addSum(nums:Int*): Int = {
    nums.sum
  }
  def main(args: Array[String]): Unit = {
    println(add(num1 = 1, num2 = 2))
    println("计算阶乘："+facrorial(num = 4))
    println("斐波那契数列："+fibonacci(6))
    //调用函数时，使用函数中参数的默认值
    println(add2())
    //调用函数时，给函数的参数重新赋值
    println(add2(30,40))
    //在调用函数时，不按照函数定义的参数顺序来传递值，而是使用带名参数的方式来传值
    println(add2(y=60,x=50))
    println(addSum(1))
    println(addSum(1, 2, 3))
    println(addSum(1, 2, 3, 4, 5))
    //使用 parameter：_*的形式，告诉编译器这个参数被当成参数序列处理
    println(addSum(1 to 10:_*))
  }
}


 5.懒值
  
  当 val 被声明为lazy时(var不能声明为lazy)，它的初始化将被推迟，直到首次对此取值，适用于初始化
开销较大的场景。
  
package lagou.cn.part02

import scala.io.BufferedSource

/**
 * 在Scala中提供可lazy的特性
 * 如果将一个变量声明一个lazy，那么只有第一次使用这个变量时，变量对应的表达式才会发生计算
 * 这种特性对于特别耗时的计算操作特别有用
 * 比如：初始化开销较大的场景，对于文件进行IO、进行网络IO的操作等
 */
object LazyDemo {
  def main(args: Array[String]): Unit = {
    //使用lazy关键字之后，即使文件不存在了，也不会报错
    //只有第一次使用变量时才会报错
    lazy val file1 =scala.io.Source.fromFile("src/test.scala")
    println("OK!")
    file1.getLines().size
  }
}


 6.文件操作
   
   导入scala.io.Source后，可引用Source中的方法读取文本文件的内容

import scala.io.{BufferedSource, Source}

object FileDemo {
  def main(args: Array[String]): Unit = {
    //注意文件的编码格式，如果编码格式不对，那么读取报错
    val file: BufferedSource = Source.fromFile("... ...", "GBK");
    val lines: Iterator[String] = file.getLines()

	for (line <- lines) {
      println(line)
    }

	//注意关闭文件
    file.close()
  }
}
  
package lagou.cn.part02
import java.io.PrintWriter

import scala.io.{BufferedSource, Source}
/**
 * I/O 操作是一门编程语言的重要内容
 * 相对于Java语言中的I/O类，Scala中的I/O的类数量较少，最常用的是Source这个类
 * 在Scala中，更多的是调用Java中的 I/O 类或者通过Java中的I/O类进行相应封装来实现I/O操作
 */
object FileDemo {
  //读取文本文件
  def readTextFile: Unit = {
    val file=Source.fromFile("src\\text.txt")
    val lines: Iterator[String] = file.getLines()

    for (line <-lines) {
      println(line)
    }
    //关闭文件
    file.close()
  }
  //读取网络资源，需要在联网状态下
  def readNetSource: Unit ={
    val source: BufferedSource = Source.fromURL("http://www.baidu.com")
    val message: String = source.mkString

    println(message)

    source.close()

  }
  //写入文本文件
  //Scala中没有内建的对写入文件的支持，需要使用java.io.PrintWriter来实现
  def writeTextFile: Unit ={
    val writer=new PrintWriter("src\\text.txt")
    for(i <- 1 to 10) {
      //写入文件内容
      writer.println(s"i = $i")
      writer.flush()
    }
    // 关闭写入流
    writer.close()
  }

  def main(args: Array[String]): Unit = {
    readTextFile
    println("=========================================")
    readNetSource
    println("=========================================")
    writeTextFile
  }
}
